home *** CD-ROM | disk | FTP | other *** search
- \chapter{Generating Runtime Applications} \label{sec:runtime}
- This chapter describes the features of SWI-Prolog for delivering
- applications that can run without the development version of the
- system installed.
- A SWI-Prolog built application consists of at least two parts: the
- emulator and the compiled application. The latter is in the same format
- as a SWI-Prolog boot-file and SWI-Prolog pre-compiled (QLF) file. This
- format is fast loadable and abstracted just far enough to be machine
- independent. This implies an application delivered in binary format
- can run on any computer for which an emulator is available without
- modification.
- \begin{description}
- \predicate{qsave_program}{2}{+File, +ListOfOptions}
- Saves the current state of the program to the file \arg{File}. The
- result is an executable shell-script, that will start the emulator.
- \arg{ListOfOptions} is a list of $<Key> = <Value>$ or $<Key>(<Value>)$
- pairs. The available keys are described in \tabref{qsave-options}.
- \begin{table}
- \begin{center}
- \begin{tabular}{|l|c|c|l|}
- \hline
- \bf Key & \bf Option & \bf Type & \bf Description \\
- \hline
- local & \bf -L & K-bytes & Size (Limit) of local stack \\
- global & \bf -G & K-bytes & Size (Limit) of global stack \\
- trail & \bf -T & K-bytes & Size (Limit) of trail stack \\
- argument & \bf -A & K-bytes & Size (Limit) of argument stack \\
- goal & \bf -g & atom & Initialisation goal \\
- toplevel & \bf -t & atom & Prolog toplevel goal \\
- init_file& \bf -f & atom & Personal initialisation file \\
- \hline
- autoload & & bool & If true, run autoload/0 first \\
- map & & atom & File containing info on dump \\
- op & & \tt save/standard & Save operator declarations? \\
- stand_alone & & bool & Include the emulator in the state \\
- \hline
- \end{tabular}
- \end{center}
- \caption{<Key> = <Value> pairs for qsave_program/2}
- \label{tab:qsave-options}
- \end{table}
- The \program{/bin/sh} script contains the following data:
- \begin{enumerate}
- \item The \jargon{shell script header} starts as:
- \begin{code}
- #!/bin/sh
- #SAVE-VERSION=<num>
- #PROLOG-VERSION=<num>
- exec ${SWIPL-/path-to-emulator} -x $0 "$@"
- \end{code}
- \item The \jargon{settings section} contains the default values
- for the various command line options.
- \item The \jargon{predicates section} contains all predicates from
- the currently running system. Clauses of predicates defined as
- \jargon{volatile} (see volatile/1) are \strong{not} saved. Neither
- are foreign predicates (see also below).
- \item The \jargon{record section} contains the database records saved
- with recorda/3 and friends. The current version saves records
- using directives.
- \item The \jargon{flag section} contains the global flags saved using
- the flag/3 predicate. Flags are saved as directives.
- \item The \jargon{feature section} contains all features that do not
- originate from the emulator itself. See set_feature/2.
- \item The \jargon{import section} contains the imports as far as they
- are not handled by the auto-import system. That is, an import
- is stored if the module is \const{user} or the module
- \const{user} contains a different definition as the one
- imported in the target module.'
- \end{enumerate}
- Before writing the data to file, qsave_program/2 will run autoload/0 to
- all required autoloading the system can discover. See autoload/0.
- Provided the application does not require any of the Prolog libraries to
- be loaded at runtime, the only file from the SWI-Prolog development
- environment required is the emulator itself. The emulator may be built
- in two flavours. The default is the \jargon{development emulator}. The
- \jargon{runtime emulator} is similar, but lacks the tracer. The stand-alone
- program \manref{chpl}{1} may be used to change the default path
- to the emulator.
- If the option \exam{stand_alone(on)} is present, the emulator is
- prepended for the state. If the emulator is started and no state is
- specified using the \cmdlineoption{-x}{} flag, it will test whether a
- boot-file (state) is attached to the emulator itself and load this
- state. Provided the application has all libraries loaded, the resulting
- file may be started anywhere.
- \predicate{qsave_program}{1}{+File}
- Equivalent to \exam{qsave_program(File, [])}.
- \predicate{autoload}{0}{}
- Check the current Prolog program for predicates that are referred to,
- are undefined and have a definition in the Prolog library. Load the
- appropriate libraries.
- This predicate is used by qsave_program/[1,2] to ensure the saved state
- will not depend on one of the libraries. The predicate autoload/0 will
- find all \strong{direct} references to predicates. It does not find
- predicates referenced via meta-predicates. The predicate {log}/2 is
- defined in the library(quintus) to provide a quintus compatible means to
- compute the natural logarithm of a number. The following program will
- behave correctly if its state is executed in an environment where the
- library(quintus) is not available:
- \begin{code}
- logtable(From, To) :-
- From > To, !.
- logtable(From, To) :-
- log(From, Value),
- format('~d~t~8|~2f~n', [From, Value]),
- F is From + 1,
- logtable(F, To).
- \end{code}
- However, the following implementation refers to {log}/2 through the
- meta-predicate maplist/3. Autoload will not be able to find the
- reference. This problem may be fixed either by loading the
- module libtary(quintus) explicitly or use require/1 to tell the
- system that the predicate {log}/2 is required by this module.
- \begin{code}
- logtable(From, To) :-
- findall(X, between(From, To, X), Xlist),
- maplist(log, Xlist, SineList),
- write_table(Xlist, SineList).
- write_table([], []).
- write_table([I|IT], [V|VT]) :-
- format('~d~t~8|~2f~n', [I, V]),
- write_table(IT, VT).
- \end{code}
- \prefixop{volatile}{+Name/Arity, \ldots}
- Declare that the clauses of specified predicates should \strong{not} be
- saved to the program. The volatile declaration is normally used to
- avoid that the clauses of dynamic predicates that represent data for
- the current session is saved in the state file.
- \end{description}
- \section{Limitations of qsave_program}
- There are three areas that require special attention when using
- qsave_program/[1,2].
- \begin{itemize}
- \item
- If the program is an embedded Prolog application or uses the foreign
- language interface, care has to be taken to restore the appropriate
- foreign context. See \secref{qforeign} for details.
- \item
- If the program uses directives (\exam{:- goal.} lines) that perform
- other actions then setting predicate attributes (dynamic, volatile,
- etc.) or loading files (consult, etc.), the directive may need to be
- prefixed with initialization/1.
- \item
- `Database references as returned by clause/3, recorded/3, etc.
- are not preserved and may thus not be part of the database when saved.
- \end{itemize}
- \section{Runtimes and Foreign Code}
- \label{sec:qforeign}
- Some applications may need to use the foreign language interface.
- Object code is by definition machine-dependent and thus cannot be
- part of the saved program file.
- To complicate the matter even further there are various ways of
- loading foreign code:
- \begin{itemlist}
- \item [Using the library(shlib) predicates]
- This is the preferred way of dealing with foreign code. It loads quickly
- and ensures an acceptable level of independence between the versions of
- the emulator and the foreign code loaded. It works on Unix machines
- supporting shared libraries and library functions to load them. Most
- modern Unixes satisfy this constraint.%
- \footnote{Linux with the old a.out format does \strong{not}}.
- It also works on the Win32 platform: Windows-NT, '95 and Windows 3.1
- running win32s.
- \item [Static linking]
- This mechanism works on all machines, but generally requires the same
- C-compiler and linker to be used for the external code as is used to
- build SWI-Prolog itself. This mechanism is the preferred way if shared
- libraries are not supported.
- \item [Using {load_foreign/[2,5]}]
- Basically only works on Unix system supporting the a.out format
- executables. This mechanism is slow and non-portable. It should be
- avoided whenever possible.
- \end{itemlist}
- To make a runtime executable that can run on multiple platforms one
- must make runtime checks to find the correct way of linking. Suppose
- we have a source-file {\tt myextension} defining the installation
- function \funcref{install}{}.
- If this file is compiled to a shared library, load_foreign_library/1
- will load this library and call the installation function to initialise
- the foreign code. If it is loaded as a static extension, define
- \funcref{install}{} as the predicate install/0:
- \begin{code}
- static foreign_t
- pl_install()
- { install();
- PL_succeed;
- PL_extension PL_extensions [] =
- /*{ "name", arity, function, PL_FA_<flags> },*/
- { "install", 0, pl_install, 0 },
- { NULL, 0, NULL, 0 } /* terminating line */
- \end{code}
- Now, use the following Prolog code to load the foreign library:
- \begin{code}
- load_foreign_extensions :-
- current_predicate(install, install), !, % static loaded
- install.
- load_foreign_extensions :- % shared library
- load_foreign_library(foreign(myextension)).
- :- initialization load_foreign_extensions.
- \end{code}
- The path alias \const{foreign} is defined by file_search_path/2. By
- default it searches the directories \file{<home>/lib/<arch>} and
- \file{<home>/lib}. The application can specify additional rules for
- file_search_path/2.
- \section{Finding Application files}
- If your application uses files that are not part of the saved program
- such as database files, configuration files, etc., the runtime version
- has to be able to locate these files. The file_search_path/2 mechanism
- in combination with the \cmdlineoption{-p}{alias} command-line argument
- is the preferred way to locate runtime files. The first step is to
- define an alias for the toplevel directory of your application. We will
- call this directory \file{gnatdir} in our examples.
- A good place for storing data associated with SWI-Prolog runtime systems
- is below the emulator's home-directory. \const{swi} is a predefined alias
- for this directory. The following is a useful default definition for
- the search path.
- \begin{code}
- user:file_search_path(gnatdir, swi(gnat)).
- \end{code}
- The application should locate all files using absolute_file_name.
- Suppose gnatdir contains a file {\tt config.pl} to define local
- configuration. Then use the code below to load this file:
- \begin{code}
- configure_gnat :-
- ( absolute_file_name(gnatdir('config.pl'), ConfigFile)
- -> consult(ConfigFile)
- ; format(user_error, 'gnat: Cannot locate config.pl~n'),
- halt(1)
- ).
- \end{code}
- \section{Using chpl for Configuration Information}
- \subsection{Changing the emulator of a runtime application}
- The program chpl, may be used to manipulate the header of a SWI-Prolog
- bootfile or state created with qsave_program/[1,2].
- It will be used most commonly by the installer of a SWI-Prolog runtime
- application to specify the path to the emulator. If the end-user decided
- to install the SWI-Prolog runtime environment in
- \begin{code}
- /usr/local/lib/rt-pl-2.1.4
- \end{code}
- the gnat application can be told to use this emulator using:
- \begin{code}
- % /usr/local/lib/rtpl-2.1.4/bin/chpl -e /usr/local/lib/rt-pl-2.1.4/bin/pl gnat
- \end{code}
- Now, {\tt gnat} may be installed in any public or private directory for
- binaries.
- \subsection{Passing a path to the application}
- Suppose the system administrator has installed the SWI-Prolog runtime
- environment in \file{/usr/local/lib/rt-pl-2.1.4}. A user wants to
- install \file{gnat}, but gnat will look for its configuration in
- \file{/usr/local/lib/rt-pl-2.1.4/gnat} where the user cannot write.
- The user decides to install the gnat runtime files in
- \file{/users/bob/lib/gnat}. For one-time usage, the user may decide
- to start gnat using the command:
- \begin{code}
- % gnat -p gnatdir=/users/bob/lib/gnat
- \end{code}
- For a more widely used executable, this is not very comfortable. The
- user may decide to edit the shell-script part of gnat. Upto the line
- holding
- \begin{code}
- # End Header
- \end{code}
- gnat is a simple \program{/bin/sh} script. After this line, the file is
- binary and may contain long lines. Most editors are not capable of
- editing such files.%
- \footnote{If you use GNU-Emacs, make sure \const{require-final-newline}
- is set to \const{nil}}
- Instead of editing the file directly, the program \manref{chpl}{1} may be
- used to extract and replace the header of \file{gnat}. The following
- editing sequence will work with any editor capable of editing ASCII
- files.
- \begin{code}
- % chpl -x gnat > gnat.hdr
- % emacs gnat.hdr
- % chpl -h gnat.hdr gnat
- \end{code}
- The header may be changed to the following to install gnat properly:
- \begin{code}
- #!/bin/sh
- # SWI-Prolog version: 2.1.4
- # SWI-Prolog save-version: 25
- exec ${SWIPL-/usr/local/lib/rt-pl-2.1.4/bin/pl} -x $0 \
- -p gnatdir=/users/bob/lib/gnat "$@"
- \end{code}
- \section{The Runtime Environment}
- \subsection{The Runtime Emulator}
- The sources may be used to built two versions of the emulator. By
- default, the \jargon{development emulator} is built. This emulator
- contains all features for interactive development of Prolog
- applications. If the system is configured using
- \cmdlineoption{--enable-runtime}{}, \manref{make}{1} will create a
- \jargon{runtime version} of the emulator. This emulator is equivalent to
- the development version, except for the following features:
- \begin{itemlist}
- \item [No input editing]
- The GNU library \clib{-lreadline} that provides EMACS compatible editing
- of input lines will not be linked to the system.
- \item [No tracer]
- The tracer and all its options are removed, making the system a little
- faster too.
- \item [No profiler]
- profile/3 and friends are not supported. This saves some space and
- provides better performance.
- \item [No interrupt]
- Keyboard interrupt (Control-C normally) is not rebound and will normally
- terminate the application.
- \item [feature(runtime, true) succeeds]
- This may be used to verify your application is running in the runtime
- environment rather than the development environment.
- \item [clause/[2,3] do not work on static predicates]
- This feature inhibits listing your program. It is only a very limited
- protection however.
- \end{itemlist}
- The following fragment is an example for building the runtime
- environment in \file{\env{HOME}/lib/rt-pl-2.1.4}. If possible, the
- shared-library interface should be configured to ensure it can serve a
- large number of applications.
- \begin{code}
- % cd pl-2.1.4
- % mkdir runtime
- % cd runtime
- % ../src/configure --enable-runtime --prefix=$HOME
- % make
- % make rt-install
- \end{code}
- The runtime directory contains the components listed below. This
- directory may be tar'ed and shipped with your application.
- \begin{center}
- \begin{tabular}{|l|l|}
- \hline
- \file{README.RT} & Info on the runtime environment \\
- \hline
- \file{bin/pl} & The emulator itself \\
- \file{bin/chpl} & The utility to change the runtime \\
- \hline
- \file{man/chpl.1} & Manual page for chpl \\
- \file{man/pl.1} & Manual page for pl \\
- \hline
- \file{swipl} & pointer to the home directory (.) \\
- \hline
- \file{lib/} & directory for shared libraries \\
- \file{lib/<arch>/} & machine-specific shared libraries \\
- \hline
- \end{tabular}
- \end{center}
-